﻿using System;
using System.Drawing;
using System.Collections.Generic;
using Noris.Schedule.Support.Core;
using Noris.Schedule.Support.Data;

namespace Noris.Schedule.Support.Services
{
	#region INTERFACE IDataSource : obecný datový zdroj
	/// <summary>
	/// Interface, definující obecný datový zdroj.
	/// Datový zdroj je objekt, který obsahuje metody specifikované v tomto interface.
	/// Metody jsou volány z grafické komponenty, v případě kdy komponenta potřebuje data k zobrazování, nebo kdy komponenta ukládá data.
	/// </summary>
	public interface IDataSource
	{
		/// <summary>
		/// Vlastnosti datového zdroje. Jde o statické informace.
		/// </summary>
		DataSourceProperties Properties { get; }
		/// <summary>
		/// Aktuální informace, zda datový zdroj může přijmout asynchronní požadavek.
		/// Má vrátit true tehdy, pokud je na to naprogramován,
		/// a současně v delegátu this.RequestCompleted je odkaz na metodu, kterou je možno volat po dokončení requestu.
		/// </summary>
		bool AcceptRequestAsync { get; }
		/// <summary>
		/// Zařadí požadavek do fronty práce, hned na její začátek, a počká na dokončení.
		/// Výsledky procesu jsou uloženy v parametru request.
		/// Po dokončení není volán delegát RequestCompleted.
		/// </summary>
		/// <param name="request">Požadovaná operace</param>
		void RunRequestSync(DataSourceRequest request);
		/// <summary>
		/// Zařadí požadavek do fronty práce, nečeká na její dokončení, ihned vrací řízení.
		/// Po dokončení jsou výsledky odeslány do delegáta RequestCompleted.
		/// Výsledky procesu jsou do něj předány v parametru request.
		/// Pokud není vyplněn delegát RequestCompleted, je vyvolána chyba.
		/// Metoda nemusí být funkčně implementována u datových zdrojů, které deklarují CanBeAsynchronous = false.
		/// </summary>
		/// <param name="request">Požadovaná operace</param>
		void RunRequestAsync(DataSourceRequest request);
		/// <summary>
		/// Řízení asynchronní operace datového zdroje, umožní pozastavit / rozběhnout asynchronní operace.
		/// false = default = asynchronní operace normálně probíhají / true = asynchronní operace jsou pozastaveny.
		/// Pokud datový zdroj nepodporuje asynchronní operace (deklaruje CanBeAsynchronous = false), nechť implementuje standardní property bez rozšířené funkcionality.
		/// Pokud datový zdroj podporuje asynchronní operace, může pro jejich řízení využít třídu Aps.Core.WorkQueueCls, kde je property WaitAsyncQueue řádně implementována.
		/// Pak stačí propojit property IDataSource.WaitAsyncQueue na WorkQueueCls.WaitAsyncQueue
		/// </summary>
		bool WaitAsyncQueue { get; set; }
		/// <summary>
		/// Vrací počet čekajících asynchronních operací, typicky pro zobrazení ve stavovém řádku.
		/// Pokud datový zdroj nepodporuje asynchronní operace (deklaruje CanBeAsynchronous = false), nechť vrátí 0.
		/// Pokud datový zdroj podporuje asynchronní operace, může pro jejich řízení využít třídu Aps.Core.WorkQueueCls, kde je property AsynchronousOperationCount řádně implementována.
		/// Pak stačí propojit property IDataSource.AsynchronousOperationCount na WorkQueueCls.AsynchronousOperationCount
		/// </summary>
		int AsynchronousOperationCount { get;}
		/// <summary>
		/// Metoda upřednostní požadavky aktivního grafu na úkor požadavků neaktivních grafů.
		/// Jinými slovy, zajistí, že asynchronní požadavky, která vydal aktivní graf, se budou realizovat dříve, než požadavky jiných grafů.
		/// Metoda se typicky volá po přepnutí aktivního grafu. Zajistí, že požadavky nyní aktivního grafu se vyřídí dříve, 
		/// než dojde řada na vyřizování nevyřízených požadavků z grafů, které nejsou aktivní.
		/// Metoda nemusí být funkčně implementována u datových zdrojů, které deklarují CanBeAsynchronous = false.
		/// </summary>
		/// <param name="activeGraphId"></param>
		void ActivateAsyncRequestForGraphId(int activeGraphId);
		/// <summary>
		/// Delegát na metodu, která bude spuštěna vždy poté, kdy je dokončena asynchronní práce na jednom každém požadavku.
		/// Metoda dostává jako parametr ten požadavek, který byl předán k vyřízení.
		/// Požadavek má vyplněné Result údaje.
		/// Tento delegát se nevolá pro synchronní požadavky.
		/// Delegát nemusí být vyplněn u datových zdrojů, které deklarují CanBeAsynchronous = false.
		/// </summary>
		Action<DataSourceRequest> RequestCompleted { get; set; }
		/// <summary>
		/// Event, který datový zdroj zavolá po každé změně počtu asynchronních požadavků.
		/// Pokud datový zdroj nepodporuje asynchronní operace (deklaruje CanBeAsynchronous = false),
		/// pak tento event sice musí obsahovat, ale nebude jej nikdy volat.
		/// Pokud datový zdroj pro řízení asynchronních operací využívá třídu Aps.Core.WorkQueueCls,
		/// pak bude volat event AsyncRequestCountChanged přímo z handleru eventu WorkQueueCls.WorkQueueCountChanged, včetně předání parametru e.
		/// </summary>
		event Noris.Schedule.Support.Core.WorkQueueCountChangedDelegate AsyncRequestCountChanged;
		/// <summary>
		/// Vrátí barvu pro kreslení určitého elementu
		/// </summary>
		/// <param name="graphType">Typ grafu</param>
		/// <param name="visualType">Vizuální typ elementu</param>
		/// <returns>Barva tohoto elementu</returns>
		System.Drawing.Color GetColorForElement(RowGraphMode graphType, GraphElementVisualType visualType);
		/// <summary>
		/// Metoda, která má za úkol vrátit soupis GID vedlejších prvků k danému prvku.
		/// Tato metoda se použije pouze v procesu editace, kdy editovaný blok dat (sada operací, atd) neobsahuje všechny prvky, na které se odkazuje.
		/// Typicky to nastane v situaci, kdy prvek 30 se odkazuje na následující prvek 40, ale ten neexistuje.
		/// Tato metoda pak musí vrátit GID prvku, který má navazovat na prvek 40 => tj. typicky půjde o prvek 50.
		/// Pokud elementy, vrácené metodou RunRequestXxx(DataSourceRequestType.ElementsRead) vrací kompaktní skupiny dat, kde nejsou díry, 
		/// pak zdejší metoda GetNearbyGIDs() může vždy vracet null.
		/// </summary>
		/// <param name="gID">GID výchozího prvku</param>
		/// <param name="orientation">Směr, v němž hledáme další prvky</param>
		/// <returns>Soupis GIDů, které v daném směru navazují. Může být null.</returns>
		IEnumerable<GID> GetNearbyGIDs(GID gID, ElementRelationOrientation orientation);
	}
	#endregion
	#region CLASS DataSourceProperties
	/// <summary>
	/// Třída, která popisuje vlastnosti datového zdroje.
	/// Podle těchto vlastností se s tímto zdrojem zachází.
	/// </summary>
	public class DataSourceProperties
	{
		/// <summary>
		/// Datový zdroj umí pracovat asynchronně = zpracovávat požadavky v privátním pracovním vláknu, 
		/// a po jejich dokončení volat metodu RequestCompleted
		/// </summary>
		public bool IsAsynchronous { get; set; }
		/// <summary>
		/// Třída umí vygenerovat mapu vztahů mezi elementy
		/// </summary>
		public bool MakeRelationMap { get; set; }
		/// <summary>
		/// Název datového zdroje
		/// </summary>
		public string SourceName { get; set; }
	}
	#endregion
	#region INTERFACE IDataRow : jeden řádek grafu
	/// <summary>
	/// Interface, definující jeden řádek grafu
	/// </summary>
	public interface IDataRow
	{
		/// <summary>
		/// Globální identifikátor tohoto záznamu.
		/// </summary>
		GID GId { get; }
		/// <summary>
		/// Reference záznamu (zakázky, výrobního příkazu, operace, pracoviště, kapacitní jednotky, ...)
		/// </summary>
		string Refer { get; set; }
		/// <summary>
		/// Název záznamu (zakázky, výrobního příkazu, operace, pracoviště, kapacitní jednotky, ...)
		/// </summary>
		string Name { get; set; }
		/// <summary>
		/// Příznak, zda tento řádek má své pod-uzly (subnodes), tj. můžeme pro něj zobrazit ikonku [+] ve stromu
		/// </summary>
		bool HasSubNodes { get; set; }
		/// <summary>
		/// Druh grafu, který je pro tento řádek zobrazen
		/// </summary>
		RowGraphMode RowGraph { get; set; }
		/// <summary>
		/// Násobek obvyklé výšky řádku pro tuto položku.
		/// Default = 1 pro běžné textové řádky.
		/// </summary>
		float RowHeightMultiplier { get; set; }
		/// <summary>
		/// Globální identifikátor záznamu parenta.
		/// Typicky se parent nevepisuje: systém typicky funguje tak, že parent je ten objekt, pro který jsou načítány jeho podřízené prvky.
		/// RowGId lze setovat. Vizuální vrstva jej přebírá po vrácení dat, ale pro svoji další interní práci si uchovává RowGId jinde.
		/// Vztah na Parenta je tedy řešen na úrovni grafiky, která požádala o načtení podřízených záznamů.
		/// Nicméně je možno při načítání podřízených záznamů rovnou načíst i hlubší podřízené záznamy, a jim pak vyplnit RowGId na explicitní záznam.
		/// Například: máme načíst všechny operace pro jeden výrobní příkaz.
		/// Načteme 6 operací, a do nich nevyplňujeme RowGId (což je defaultní chování).
		/// Nad rámec operací se rozhodneme načíst i komponenty operací, tedy podřízené řádky.
		/// Pak pro každou ze 6 operací najdeme její komponenty, načteme je, do každé komponenty vložíme RowGId = GId její operace, 
		/// a komponenty přidáme do výsledného seznamu dat. Sestavení struktury stromu pak zajistí vizuální vrstva.
		/// Toto je navíc i rekurzivní možnost.
		/// </summary>
		GID ParentGId { get; set; }
		/// <summary>
		/// Pole elementů (časové položky grafu), které jsou načítány společně s řádkem.
		/// Ve výchozím stavu je null !
		/// Některé datové typy jsou konstruovány tak, že časová položka je nedílnou součástí řádku 
		/// (např. operace výrobního příkazu je současně řádkem grafu, a současně časovou položkou). 
		/// Pak je vhodné vygenerovat časové položky společně s položkou řádku, a uložit informace do tohoto pole.
		/// Metoda GetRows tak vyřeší načítání jak řádku, tak časových elementů.
		/// Pokud jsou touto metodou načteny všechny časové úseky (např. může existovat jen jeden čas, a ten je uložen do tohoto pole),
		/// pak je třeba nastavit this.AllElementsLoaded = true, a řídící jednotka grafu pak nebude nikdy donačítat data pro širší časové úseky.
		/// Tento mechanismus se nehodí pro objekty, které mají časově široké rozmístění mnoha elementů, typicky stavy kapacit.
		/// </summary>
		List<IDataElement> ElementList { get; set; }
		/// <summary>
		/// Příznak, že elementy načtené do pole this.ElementList představují úplnou sadu elementů, 
		/// a pro tento řádek (this) nebude nikdy zapotřebí donačítat elementy pro širší časové pole.
		/// </summary>
		bool AllElementsLoaded { get; set; }
		/// <summary>
		/// Příznak, že elementy načtené do pole this.ElementList představují úplnou sadu elementů pro určitý (tento) WorkGID.
		/// Víc elementů pro tento WorkGID neexistuje. Typicky se nastavuje na neprázdný WorkGID při iniciaci dat osy S nebo osy C,
		/// kde se načítá jen jeden element pro jeden konkrétní WorkGID.
		/// Zůstává Empty při načítání elementů kapacitní jednotky, kde nelze předem načíst celý WorkList.
		/// </summary>
		GID WorkGIDAllElementsLoaded { get; set; }
		/// <summary>
		/// Ikona pro tento řádek
		/// </summary>
		System.Drawing.Image Icon { get; }
		/// <summary>
		/// Akce grafické vrstvy po vstupu na řádek, typicky None
		/// </summary>
		RowActionType ActionOnEnter { get; }
		/// <summary>
		/// Akce grafické vrstvy po kliknutí na řádek, typicky None
		/// </summary>
		RowActionType ActionOnClick { get; }
		/// <summary>
		/// Akce grafické vrstvy po double kliknutí na řádek, typicky None
		/// </summary>
		RowActionType ActionOnDoubleClick { get; }
        /// <summary>
        /// Deklarace vlastnsotí řádku.
        /// Může být null, pak se kompletně přebírá ze stejnojmenné property v deklaraci grafu (GraphDeclarationCls.RowGraphDeclaration).
        /// </summary>
        DataRowGraphDeclaration RowGraphDeclaration { get; }
		/// <summary>
		/// Vrátí text, který se zobrazuje v ToolTipu.
		/// Může vrátit null, pak se za tento objekt nic nezobrazí.
		/// Může vrátit text, obsahující CrLf, pak bude text odřádkován.
		/// </summary>
		string ToolTipInfo();
	}
	#endregion
	#region INTERFACE IDataElement : jeden grafický element grafu
	/// <summary>
	/// Interface, definující jeden grafický element grafu
	/// </summary>
	public interface IDataElement
	{
		/// <summary>
		/// Globální identifikátor záznamu = tohoto elementu
		/// </summary>
		GID GId { get; }
		/// <summary>
		/// Globální identifikátor rodičovského záznamu = řádek, v kterém se element nachází.
		/// Pokud je toto čas operace, pak parentem je operace.
		/// Pokud tento element je čas stavu kapacit, jde o kapacitní jednotku.
		/// Pokud tento element představuje část práce z konkrétní operace na konkrétní kapacitě, pak bude zobrazen na dané kapacitě.
		/// Jde o aktuální údaj, který může obsahovat editovanou hodnotu.
		/// </summary>
		GID RowGId { get; set; }
		/// <summary>
		/// Globální identifikátor rodičovského záznamu = řádek, v kterém se element nachází.
		/// Jde o původní údaj, načtený z databáze. Grafický element jej nemůže změnit.
		/// </summary>
		GID OriginalRowGId { get; }
		/// <summary>
		/// Globální identifikátor pracovní jednotky: jedna pracovní jednotka může být zobrazena ve více grafech (různé typy grafů),
		/// a v rámci jednoho grafu může být jedna práce zobrazena ve více časových elementech (časově roztrhaná práce), ale přesto je to jeden pracovní úkol.
		/// </summary>
		GID WorkGId { get; }
		/// <summary>
		/// Globální identifikátor nadřízené pracovní jednotky: původce tohoto pracovního úseku.
		/// Pokud tento element je práce na operaci, pak parentem je výrobní příkaz/dílec.
		/// Pokud tento element je dílec, pak parentem může být zakázka, nebo nic.
		/// Pokud tento element je stav kapacit, pak parenta nemá: do parenta se promítají změny v čase této operace, a stav kapacit nelze změnit přetáhnutím.
		/// </summary>
		GID ParentWorkGId { get; }
		/// <summary>
		/// Globální identifikátor podřízených záznamů. Obsahuje WorkGId záznamů elementů, které jsou podřízené tomuto elementu.
		/// Lze tak sestavit mapu (strom) 
		/// </summary>
		GID[] FirstChildWorkGIds { get; }
		/// <summary>
		/// Globální identifikátor WorkGId pracovních úkolů, které předcházejí výkonu práce na elementech this.WorkGId
		/// </summary>
		GID[] PreviousWorkGIds { get; }
		/// <summary>
		/// Globální identifikátor WorkGId pracovních úkolů, které následují po výkonu práce na elementech this.WorkGId
		/// </summary>
		GID[] NextWorkGIds { get; }
		/// <summary>
		/// Časový interval tohoto elementu (od kdy do kdy trvá).
		/// Jde o aktuální údaj, který může obsahovat editovanou hodnotu.
		/// </summary>
		TimeRange TimeRange { get; set; }
		/// <summary>
		/// Časový interval tohoto elementu (od kdy do kdy trvá).
		/// Jde o původní údaj, načtený z databáze. Grafický element jej nemůže změnit.
		/// </summary>
		TimeRange OriginalTimeRange { get; }
		/// <summary>
		/// Zlomky elementu, převezme si je vhodný painter
		/// </summary>
		float[] Fragments { get; }
		/// <summary>
		/// Příslušnost data do vrstvy.
		/// Odlišuje vrstvu podkladovou (typicky zobrazení směny) a vrstvu datovou (aktivita v čase, která může být delší / kratší než směna).
		/// </summary>
		GraphElementLayerType ElementLayer { get; }
		/// <summary>
		/// Definuje režim, jakým lze touto položkou pohybovat ( Move a Resize )
		/// a jaký vliv má tento pohyb na okolní položky ( nadřízené a sousední ).
		/// Tato proměnná má význam pouze pro vrstvu (ElementLayer == GraphElementLayerType.ItemLayer).
		/// </summary>
		DataElementEditingMode ElementEditingMode { get; }
		/// <summary>
		/// Tvar elementu.
		/// </summary>
		GraphElementShapeType ElementShapeType { get; }
		/// <summary>
		/// Barva pozadí elementu
		/// </summary>
		Color BackColor { get; }
		/// <summary>
		/// Barva písma v elementu
		/// </summary>
		Color FontColor { get; }
		/// <summary>
		/// Specifikuje druh obsahu, ovlivňuje způsob zobrazování (barvu, vzhled).
		/// Datová vrstva zde může odlišovat různé typy směn, různé režimy práce, různé úrovně hierarchie zakázky, různé zobrazované třídy.
		/// U grafu typu RowGraphMode.Gantt ovlivní barvu políčka, vyjadřuje druh činnosti.
		/// U grafu typu RowGraphMode.CapacityUtilization ovlivní barvu políčka, vyjadřuje druh směny.
		/// U grafu typu RowGraphMode.TaskCapacityLink ovlivňuje barvu políčka směny (pokud je this.ElementLayer == SubLayer), nebo práce (pokud je this.ElementLayer == ItemLayer).
		/// Konkrétní barvu generuje metoda IDataSource.GetColorForElement()
		/// </summary>
		GraphElementVisualType ElementVisualType { get; }
        /// <summary>
        /// Ikona vykreslovaná v elementu.
        /// Ikona se kreslí tak, že její střed leží na středu času Begin.
        /// Může být null.
        /// </summary>
        Image Icon { get; }
		/// <summary>
		/// Splnění úkolu, typicky u operací, které jsou částečně nebo zcela odvedeny.
		/// Zohledňuje se u grafu typu Gantt. (Typ grafu určuje RowGId (typ řádku).)
		/// Smysluplné hodnoty: 0 (= ještě se ani nezačalo) až 1 (= vše je hotovo). Hodnoty mimo rozsah 0 až 1 mají význam 0 nebo 1.
		/// </summary>
		float CompletionRatio { get; }
		/// <summary>
		/// Využití stavu kapacity v poměrné hodnotě (1.00 = 100%). Záporné hodnoty mají význam jako 0. 
		/// Hodnoty nad 1.00 značí přečerpání kapacit a zobrazují se.
		/// </summary>
		float UtilizationRatio { get ; }
		/// <summary>
		/// Poměrné využití výrobní linky pro tuto operaci (podílové využití)
		/// </summary>
		float UseRatio { get; }
		/// <summary> { get; set; }
		/// Číslo linkovací skupiny, typicky číslo subjektu ve vztahu "lcs.plan_unit_c_task.link".
		/// Hodnota 0 = není link, tento záznam není nijak spojen s jinými záznamy.
		/// </summary>
		int LinkGroup { get; }
		/// <summary>
		/// Vrátí text, který se zobrazuje v ToolTipu.
		/// Může vrátit null, pak se za tento objekt nic nezobrazí.
		/// Může vrátit text, obsahující CrLf, pak bude text odřádkován.
		/// </summary>
		string ToolTipInfo(IDataRow rowData);
		/// <summary>
		/// Vrátí text, který se zobrazuje v obdélníku elementu při jeho "zaměření", například při editaci.
		/// Jde o krátkou, zásadně jednořádkovou informaci, jejíž délka (počet znaků) je omezena 
		/// fyzickou velikostí elementu při aktuálním rozlišení.
		/// </summary>
		/// <param name="rowData">Data o řádku, v němž se element nachází. Řádek může obsahovat některé potřebné informace.</param>
		/// <param name="charCount">Nejvyšší počet aktuálně zobrazitelných znaků. 
		/// Pokud bude vrácený text obsahovat více znaků, budou pravděpodobně oříznuty. 
		/// Pravděpodobnost je způsobena proporcionálním písmem. 
		/// Daný počet znaků je vypočten na maximální šířku znaku, jde tedy o garantovaný zobrazitelný počet. 
		/// Pokud bude vrácen text delší, ale složený z užších znaků, možná se podaří je zobrazit korektně. 
		/// Jsme v grafickém prostředí Windows...</param>
		/// <returns></returns>
		string Caption(IDataRow rowData, float charCount);
        /// <summary>
        /// Režim viditelnosti elementu. Výchozí je Default (0): elementy Gantt jsou viditelné vždy, elementy TaskLink jsou viditelné jen pokud jsou nějak aktivní (myší, výběrem).
        /// </summary>
        CaptionVisibilityMode CaptionVisibility { get; }
    }
	#endregion
    #region CLASS DataRowGraphDeclaration
    /// <summary>
    /// DataRowGraphDeclaration : Deklarace vlastností řádků, dovoluje míchat řádky s různými vlastnostmi v jednom grafu (graf má vlastnosti výchozí, kterýkoli řádek může jeho vlastnosti modifikovat)
    /// </summary>
    public class DataRowGraphDeclaration
    {
        public DataRowGraphDeclaration()
        {
            this.RowColor = Color.Empty;
            this.RowHeightTotalMaxPx = 0;
            this.RowHeightTotalMinPx = 0;
            this.RowHeightLineSolidPx = 0;
            this.RowHeightLineFragmentPx = 0;
            this.RowHeightMinFragmentPx = 0;
            this.RowHeightAddLineSolidRatio = 0m;
            this.RowHeightAddLineFragmentRatio = 0m;
        }
        public DataRowGraphDeclaration(RowGraphMode defaultGraphMode)
        {
            bool isNormal = (defaultGraphMode != RowGraphMode.TaskCapacityLink);
            this.RowColor = Color.Empty;
            this.RowHeightTotalMaxPx = (isNormal ? 48 : 250);
            this.RowHeightTotalMinPx = 18;
            this.RowHeightLineSolidPx = (isNormal ? 24 : 9);
            this.RowHeightLineFragmentPx = 60;
            this.RowHeightMinFragmentPx = 4;
            this.RowHeightAddLineSolidRatio = (isNormal ? 0M : 1.00M);
            this.RowHeightAddLineFragmentRatio = (isNormal ? 0M : 0.25M);
        }
        /// <summary>
        /// Barva pozadí řádku
        /// </summary>
        public Color RowColor { get; set; }
        /// <summary>
        /// Nejvyšší výška řádku grafu, v pixelech.
        /// Rovnání do výšky se uplatňuje pouze u grafu typu RowGraphMode.TaskCapacityLink.
        /// Pokud by v grafu bylo více položek nad sebou, tak že by výška řádku překročila tuto hodnotu, 
        /// bude řádek "zhuštěný" tak, aby nepřekročil tuto výšku.
        /// Pokud bude uvedena hodnota 0, nebude se výška řádku kontrolovat.
        /// Hodnoty menší a rovno 10 budou rovněž ignorovány, z praktických důvodů zobrazování.
        /// Implicitní hodnota je 48 pixelů, avšak pro graf typu RowGraphMode.TaskCapacityLink je to 250 pixelů.
        /// </summary>
        public int RowHeightTotalMaxPx { get; set; }
        /// <summary>
        /// Nejmenší výška řádku, pod kterou neklesne ani když by neměl co zobrazit v případě TaskCapacityLink.
        /// </summary>
        public int RowHeightTotalMinPx { get; set; }
        /// <summary>
        /// Typická výška jednoho řádku.
        /// U většiny typů grafu jde o výšku celého řádku.
        /// U grafu typu RowGraphMode.TaskCapacityLink jde o výšku vyhrazenou pro jeden stroj (výška řádku je daná počtem použitých strojů).
        /// Pokud v grafu RowGraphMode.TaskCapacityLink je řádek využívaný v podílech (UseRatio je menší než 1), 
        /// pak se pro takový řádek použije výška linky ne tato (RowHeightOneLine), ale RowHeightOneFragmentedLine.
        /// Implicitní hodnota je 24 pixelů, avšak pro graf typu RowGraphMode.TaskCapacityLink je to 9 pixelů.
        /// Platná hodnota je 7 až 100 pixelů. Jiné hodnoty budou zarovnány do těchto mezí.
        /// </summary>
        public int RowHeightLineSolidPx { get; set; }
        /// <summary>
        /// Typická výška jednoho řádku, pokud jde o řádek typu RowGraphMode.TaskCapacityLink, 
        /// a na tomto řádku je detekováno podílové čerpání kapacity (UseRatio je menší než 1).
        /// Systém sám detekuje takové řádky, a vykresluje je v této výšce linky namísto výšky RowHeightOneLine.
        /// Jde opět o výšku pro jeden stroj. Pokud bude v rámci kapacitní jednotky použito více (N) strojů, bude výška řádku N× vyšší.
        /// Implicitní hodnota je 60 pixelů.
        /// Platná hodnota je 7 až 100 pixelů. Jiné hodnoty budou zarovnány do těchto mezí.
        /// </summary>
        public int RowHeightLineFragmentPx { get; set; }
        /// <summary>
        /// Výška nejmenšího zlomku v grafu typu RowGraphMode.TaskCapacityLink, kdy jsou zobrazeny položky využívající podíl kapacity.
        /// Pokud například operace využije 1/10 kapacity (plochy) stroje, a výška linky (RowHeightOneFragmentedLine) bude 30 pixelů, 
        /// pak by výška využití této 1/10 kapacity byla 3 pixely. Což je téměř neviditelné.
        /// Proto je možno deklarovat výšku minimálního zlomku: pokud v takovém případě bude RowHeightMinFragment = 6,
        /// pak fragment využívající 1/10 kapacity bude vysoký 6 pixelů, a úměrně k tomu bude výška linky = 60 pixelů (namísto zadaných 30).
        /// Implicitní hodnota je 4 pixely.
        /// Platná hodnota je 2 až 25 pixelů. Jiné hodnoty budou zarovnány do těchto mezí.
        /// </summary>
        public int RowHeightMinFragmentPx { get; set; }
        /// <summary> { get; }
        /// Přídavek k výšce neděleného řádku, vyjádřený relativně k hodnotě this.RowHeightOneLine (fyzická výška jedné linky).
        /// Přídavek je vykreslen nad horní linkou (strojem) jako prázdné místo.
        /// Implicitní hodnota je 0.00 (nic se nepřidává), avšak pro graf typu RowGraphMode.TaskCapacityLink je to 1.00
        /// </summary>
        public decimal RowHeightAddLineSolidRatio { get; set; }
        /// <summary> { get; }
        /// Přídavek k výšce děleného řádku, vyjádřený relativně k hodnotě this.RowHeightOneLine (fyzická výška jedné linky).
        /// Přídavek je vykreslen nad horní linkou (strojem) jako prázdné místo.
        /// Implicitní hodnota je 0.00 (nic se nepřidává), avšak pro graf typu RowGraphMode.TaskCapacityLink je to 0.25
        /// </summary>
        public decimal RowHeightAddLineFragmentRatio { get; set; }
    }
	#endregion
    #region CLASS DataRelation : jeden záznam o položce / vztahu mezi položkami v systému vztahů
    /// <summary>
	/// Jeden záznam do soupisu položek nebo vztahů položek, které generuje datový proces do vizuální vrstvy.
	/// Záznam je možno používat jako Key v Dictionary (má GetHashCode a Equals).
	/// Dva záznamy je možno porovnávat (porovnat shodu jejich dat) pomocí operátoru == a != 
	/// </summary>
	public class DataRelation
	{
		#region KONSTRUKCE
		/// <summary>
		/// Konstruktor pro záznam se vztahem "None" = pouze jeden pointer
		/// </summary>
		/// <param name="current">Pointer na element</param>
		public DataRelation(DataPointerStr current)
		{
			this._Current = current;
			this._Relation = ElementRelationOrientation.None;
			this._Other = new DataPointerStr();
		}
		/// <summary>
		/// Konstruktor pro záznam o vztahu mezi dvěma body
		/// </summary>
		/// <param name="current">Pointer na aktuální element</param>
		/// <param name="relation">Druh vztahu</param>
		/// <param name="other">Pointer na navázaný element</param>
		public DataRelation(DataPointerStr current, ElementRelationOrientation relation, DataPointerStr other)
		{
			this._Current = current;
			this._Relation = relation;
            this._AcceptBackTime = false;
			this._Other = other;
		}
        /// <summary>
        /// Konstruktor pro záznam o vztahu mezi dvěma body
        /// </summary>
        /// <param name="current">Pointer na aktuální element</param>
        /// <param name="relation">Druh vztahu</param>
        /// <param name="acceptBackTime">Příznak, zda vztah se záporným časem je akceptovatelný (Warning) nebo chybný (Error). Pokud bude false, pak zpětné časové přesuny budou mít červené pozadí (Error), pokud bude true pak zpětné přesuny budou Warning (oranžové linky).</param>
        /// <param name="other">Pointer na navázaný element</param>
        public DataRelation(DataPointerStr current, ElementRelationOrientation relation, bool acceptBackTime, DataPointerStr other)
        {
            this._Current = current;
            this._Relation = relation;
            this._AcceptBackTime = acceptBackTime;
            this._Other = other;
        }
        private DataPointerStr _Current;
		private ElementRelationOrientation _Relation;
        private bool _AcceptBackTime;
		private DataPointerStr _Other;
		/// <summary>
		/// Vrátí plný klon sebe sama.
		/// </summary>
		/// <returns></returns>
		public DataRelation Clone()
		{
			return new DataRelation(this._Current, this._Relation, this._AcceptBackTime, this._Other);     // Všechno to jsou value type.
		}
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			if (this.IsRelation)
				return "{Relation: " + this.Current + "  ( " + this.Relation + " )  " + this.Other + "}";
			else
				return "{Item: " + this.Current + "}";
		}
		#endregion
		#region OVERRIDES GetHashCode(), Equals()
		public override int GetHashCode()
		{
			if (this.IsRelation)
				return this._Current.GetHashCode() ^ this._Relation.GetHashCode() ^ this._Other.GetHashCode();
			// Pokud to není vztah, pak ignoruji obsah prvku _Other:
			return this._Current.GetHashCode() ^ this._Relation.GetHashCode();
		}
		public override bool Equals(object obj)
		{
			if (!(obj is DataRelation)) return false;
			return (DataRelation._IsEqual(this, (DataRelation)obj));
		}
		#endregion
		#region operator ==, !=, IComparable)
		/// <summary>
		/// Operátor "je rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator ==(DataRelation a, DataRelation b)
		{
			return DataRelation._IsEqual(a, b);
		}
		/// <summary>
		/// Operátor "není rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator !=(DataRelation a, DataRelation b)
		{
			return (!DataRelation._IsEqual(a, b));
		}
		/// <summary>
		/// Porovnání dvou instancí této struktury, zda obsahují shodná data
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		private static bool _IsEqual(DataRelation a, DataRelation b)
		{
			if (a.IsRelation)
				return (a._Current == b._Current && a._Relation == b._Relation && a._Other == b._Other);
			// Pokud to není vztah, pak ignoruji obsah prvku _Other:
			return (a._Current == b._Current && a._Relation == b._Relation);
		}
		#endregion
		#region PROPERTY
		/// <summary>
		/// Vrátí vždy novou prázdnou strukturu
		/// </summary>
		public static DataRelation Empty { get { return new DataRelation(DataPointerStr.Empty, ElementRelationOrientation.None, false, DataPointerStr.Empty); } }
		/// <summary>
		/// Pointer na element (GID řádku a GID elementu), v němž je umístěn element This.
		/// Tento element může být v seznamu uveden vícekrát, pokud má vztah na více prvků.
		/// Pokud je Relation == None, pak jde o zápis infromace o existenci elementu.
		/// </summary>
		public DataPointerStr Current { get { return this._Current; } set { this._Current = value; } }
		/// <summary>
		/// Vztah z elementu ThisElement na element OtherElement. Tedy, v jaké pozici j elementu This je element Other.
		/// Pokud je vztah = Next, pak to značí, že element OtherElement je Next (následující) za elementem ThisElement.
		/// Pokud je vztah = Parent, pak element OtherElement je Parentem elementu ThisElement.
		/// </summary>
		public ElementRelationOrientation Relation { get { return this._Relation; } }
        /// <summary>Je přípustný vztah "dozadu", kde čas ToTime.Begin je menší než čas FromTime.End</summary>
        public bool AcceptBackTime { get { return this._AcceptBackTime; } }
		/// <summary>
		/// Pointer na element (GID řádku a GID elementu), který je cílem vztahu.
		/// Pokud je Relation == None, pak je prázdný.
		/// </summary>
		public DataPointerStr Other { get { return this._Other; } set { this._Other = value; } }
		/// <summary>
		/// Vrací true, pokud tento záznam je záznamem o vztahu (tzn. typ vztahu není None, a záznam Other není prázdný).
		/// </summary>
		public bool IsRelation { get { return this.Relation != ElementRelationOrientation.None && !this.Other.IsEmpty; } }
		/// <summary>
		/// Vrátí reverzní vyjádření vztahu ke vztahu aktuálnímu (this).
		/// Nemění se význam vztahu, mění se pohled toho, kdo je Current a kdo je Other (ty dva se prohodí, a otočí se vztah).
		/// Pokud this není vztah, vrátí duplikát sebe sama.
		/// Co je to reverzní vztah:
		/// Pokud this má například tento obsah: { A [ Parent je : ] B }, pak reverzní je { B [ Child je : ] A }
		/// Nebo : { A [ PrevWork je : ] B }, pak reverzní je { B [ NextWork je : ] A }
		/// Nebo : { A [ Parallel je : ] B }, pak reverzní je { B [ Parallel je : ] A }
		/// </summary>
		public DataRelation ReverseRelation
		{
			get
			{
				if (!this.IsRelation) return new DataRelation(this.Current);
				return new DataRelation(this.Other, GetElementRelationReverse(this.Relation), this.AcceptBackTime, this.Current);
			}
		}
		/// <summary>
		/// Metoda vrátí vztah, který vychází z původního vztahu (originRelation), 
		/// ale pokud se vztah týká určitého elementu (buď Current anebo Other se odkazuje na element z parametru elementPointer),
		/// pak se vrací upravený vztah, kde je nahrazen řádek v Current anebo Other řádkem z elementPointer.
		/// </summary>
		/// <param name="originRelation"></param>
		/// <param name="elementPointer"></param>
		/// <returns></returns>
		public static DataRelation GetTransposedRelation(DataRelation originRelation, DataPointerStr elementPointer)
		{
			if (!originRelation.IsRelation)
			{	// Jednostranný záznam, nejde o vztah:
				if (originRelation.Current.Element == elementPointer.Element)
					return new DataRelation(elementPointer);
				return originRelation;
			}
			// Dvoustranný záznam, vztah:
			if (originRelation.Current.Element == elementPointer.Element || originRelation.Other.Element == elementPointer.Element)
			{
				return new DataRelation(
					DataPointerStr.GetTransposedPointer(originRelation.Current, elementPointer),
					originRelation.Relation,
                    originRelation.AcceptBackTime,
					DataPointerStr.GetTransposedPointer(originRelation.Other, elementPointer));
			}
			return originRelation;
		}
		/// <summary>
		/// Vrátí časově reverzní vztah ke vztahu zadanému.
		/// </summary>
		/// <param name="relation"></param>
		/// <returns></returns>
		public static ElementRelationOrientation GetElementRelationReverse(ElementRelationOrientation relation)
		{
			switch (relation)
			{
				case ElementRelationOrientation.None:
					return ElementRelationOrientation.None;
				case ElementRelationOrientation.Parent:
					return ElementRelationOrientation.Child;
				case ElementRelationOrientation.Child:
					return ElementRelationOrientation.Parent;
				case ElementRelationOrientation.PrevWork:
					return ElementRelationOrientation.NextWork;
				case ElementRelationOrientation.NextWork:
					return ElementRelationOrientation.PrevWork;
				case ElementRelationOrientation.PrevTask:
					return ElementRelationOrientation.NextTask;
				case ElementRelationOrientation.NextTask:
					return ElementRelationOrientation.PrevTask;
				case ElementRelationOrientation.PrevAxis:
					return ElementRelationOrientation.NextAxis;
				case ElementRelationOrientation.NextAxis:
					return ElementRelationOrientation.PrevAxis;
				case ElementRelationOrientation.Parallel:
					return ElementRelationOrientation.Parallel;
			}
			return ElementRelationOrientation.None;
		}
		#endregion
	}
	#endregion
    #region DELEGÁTI
    /// <summary>
    /// Předpis pro metodu, která pro daný pointer vrátí data jeho elementu.
    /// </summary>
    /// <param name="pointer"></param>
    /// <returns></returns>
    public delegate IDataElement FindDataElementHandler(DataPointerStr pointer);
    #endregion
    #region ENUMY
    /// <summary>
	/// Druh zobrazení grafu
	/// </summary>
	public enum RowGraphMode
	{
		/// <summary>
		/// Graf, jehož elementy se nekreslí, tzv. neviditelný graf
		/// </summary>
		NoDrawingElements = 1,
		/// <summary>
		/// Obdélníčky bez vztahů (např. zakázka)
		/// </summary>
		Sector,
		/// <summary>
		/// Gantt diagram, vztahy mezi prvky
		/// </summary>
		Gantt,
		/// <summary>
		/// Využití kapacit, procentuální využití kapacity v čase
		/// </summary>
		CapacityUtilization,
		/// <summary>
		/// Vazba mezi úkolem a konkrétní kapacitní jednotkou, pro řetízkový graf s možností přesunů v čase i v místě (nahoru/dolů)
		/// </summary>
		TaskCapacityLink,
		/// <summary>
		/// Skladová zásoba = linka vývoje zásoby v čase
		/// </summary>
		StockReserve
	}
	/// <summary>
	/// Akce po kliknutí / doubleclicku na řádek
	/// </summary>
	public enum RowActionType
	{
		/// <summary>
		/// Řádek nebude provádět žádnou akci
		/// </summary>
		None = 1,
		/// <summary>
		/// Je požadováno najít odpovídající řádek na jiném grafu
		/// </summary>
		FindRowOnNextGraph,
		/// <summary>
		/// Zavolat datový zdroj, sám řekne jaká má být akce
		/// </summary>
		CallDataSourceRequest,
		/// <summary>
		/// Změnit měřítko tak, aby se zobrazil celý element, na který se kliknulo
		/// </summary>
		ZoomTimeToCurrentElement,
		/// <summary>
		/// Změnit měřítko tak, aby se zobrazily všechny elementy načtené do grafu
		/// </summary>
		ZoomTimeToAllElements,
        /// <summary>
        /// Změnit měřítko tak, aby se zobrazil element na který se kliknulo, 
        /// anebo pokud se nekliklo na element, tak na celý obsah řádku.
        /// </summary>
        ZoomTimeToElementOrRow
	}
	/// <summary>
	/// Změna řádků v grafu po změně pozice v jiném grafu.
	/// Typicky se řádky nemění. Je možno zadat souhrn požadavků.
	/// </summary>
	[Flags]
	public enum RowListChangeMode
	{
		None = 0,
		/// <summary>
		/// Nastaví řádkový filtr na vybrané řádky (property: request.RowFilterList)
		/// </summary>
		SetFilter = 0x0001,
		/// <summary>
		/// Zruší řádkový filtr
		/// </summary>
		ResetFilter = 0x0002,
		/// <summary>
		/// Smaže všechny řádky, typicky v kombinaci s hodnotou RowListChangeMode.AcceptRowItems anebo RowListChangeMode.CallTopLevelRead
		/// </summary>
		ClearRowList = 0x0010,
		/// <summary>
		/// Akceptovat řádky, které jsou vyplněny v request.ResultItems.
		/// Touto cestou lze vyměnit řádky v grafu pomocí jednoho requestu, 
		/// na rozdíl od hodnoty RowListChangeMode.CallTopLevelRead (kdy bude vygenerován další request jen na čtení řádků).
		/// Původní obsah seznamu řádků může být smazán, pokud bude zvolena i hodnota RowListChangeMode.ClearRowList.
		/// Pokud nebude smazán, pak se řádky přidají k současným řádkům (může dojít k duplicitě v poli řádků).
		/// </summary>
		AcceptRowItems = 0x0020,
		/// <summary>
		/// Vyžádat si nové naplnění pole řádků grafu přes standardní request TopLevelRead (bude generován další request).
		/// Jednodušší je ale předat pole nových řádků přímo do tohoto requestu do property request.ResultItems 
		/// a potvrdit hodnotou RowListChangeMode.AcceptRowItems.
		/// Původní obsah seznamu řádků může být smazán, pokud bude zvolena i hodnota RowListChangeMode.ClearRowList.
		/// Pokud nebude, pak se řádky přidají k současným řádkům (může dojít k duplicitě v poli řádků).
		/// </summary>
		CallTopLevelRead = 0x0040,
		/// <summary>
		/// Invalidovat řádky, jejichž GID je uveden v poli RowsToInvalidate
		/// </summary>
		InvalidateRowGid = 0x0080
	}
	/// <summary>
	/// Vrstvy grafu
	/// </summary>
	public enum GraphElementLayerType
	{
		/// <summary>
		/// Dočasná vrstva. leží ještě pod SubLayer, vykresluje se co nejjednodušeji.
		/// </summary>
		TempLayer = 1,
		/// <summary>
		/// Podkladová vrstva = zobrazuje typicky pracovní dobu, svátky, směny = data, jimiž nelze z principu hýbat
		/// </summary>
		SubLayer,
		/// <summary>
		/// Vrstva dat = zobrazuje typicky pracovní úkoly (realitu, plán, návrhy, ...) = data, jimiž lze obecně pohybovat
		/// </summary>
		ItemLayer
	}
	/// <summary>
	/// Stav elementu
	/// </summary>
	public enum GraphElementState
	{
		/// <summary>
		/// Standardní element, který se může stát aktivním
		/// </summary>
		Standart,
		/// <summary>
		/// Element, který je neinteraktivní, mrtvý
		/// </summary>
		Dead,
		/// <summary>
		/// Element, který je vybrán (Kliknutím / rámováním), ale zatím se s ním nehýbe, není Pinned
		/// </summary>
		SelectedFree,
		/// <summary>
		/// Element, který je vybrán (Kliknutím / rámováním), ale zatím se s ním nehýbe, je fixovaný Pinned
		/// </summary>
		SelectedPinned,
		/// <summary>
		/// Element, který je zafixovaný = připíchnutý k plánovací tabuli
		/// </summary>
		Pinned,
		/// <summary>
		/// Element, kterým se nyní pohybuje (Move / Resize), nefixovaný (not Pinned)
		/// </summary>
		ActiveFree,
		/// <summary>
		/// Element, kterým se nyní pohybuje (Move / Resize), a je fixovaný (Pinned)
		/// </summary>
		ActivePinned,
		/// <summary>
		/// Element je v editoru, nefixovaný (not Pinned)
		/// </summary>
		InEditorFree,
		/// <summary>
		/// Element je v editoru, nefixovaný, a je fixovaný (Pinned)
		/// </summary>
		InEditorPinned,
		/// <summary>
		/// Element, který se nachází pod myší, ale jinak je Standard (tzn. neaktivní), nefixovaný (not Pinned)
		/// </summary>
		OnMouseFree,
		/// <summary>
		/// Element, který se nachází pod myší, ale jinak je Pinned, a je fixovaný (Pinned)
		/// </summary>
		OnMousePinned
	}
	/// <summary>
	/// Režim možnosti pohybu elementu (jeho přesování v grafu)
	/// </summary>
	[Flags]
	public enum DataElementEditingMode
	{
		/// <summary>
		/// Položku nelze přesouvat.
		/// </summary>
		DeadElement = 0,
		/// <summary>
		/// Položku lze přesouvat na jiné místo. Změnu jejího rozměru povoluje hodnota Resizable.
		/// Pokud položka není Movable, pak s ní nepohne ani změna nadřízené položky, a ani posun okolních položek.
		/// Pokud položka není Movable a ani Resizable, nelze ji vybrat k pohybům.
		/// </summary>
		Movable = 0x0001,
		/// <summary>
		/// Položku lze resizovat = změnit její velikost. O jejím přesunu na jiné místo rozhoduje hodnota Movable.
		/// Pokud položka není Resizable, pak se její velikost nezmění ani když se rozšiřuje prostor jejích potomků.
		/// Pokud položka není Movable a ani Resizable, nelze ji vybrat k pohybům.
		/// </summary>
		Resizable = 0x0002,
		/// <summary>
		/// Položku lze přemístit na jiný řádek (transpozice = jako v notové osnově, nahoru / dolů).
		/// </summary>
		TransponableToAnotherRow = 0x0004,
		/// <summary>
		/// Položku lze aktivovat, tím se rozsvítí její vztahy. Ale nelze ji přesouvat.
		/// </summary>
		Selectable = 0x0008,
		/// <summary>
		/// Souhrn hodnot Movable | Resizable | TransponableToAnotherRow. 
		/// </summary>
		Editable = Movable | Resizable | TransponableToAnotherRow,
		/// <summary>
		/// Při přesouvání této položky se přesouvají i okolní položky (na stejné úrovni).
		/// V této volbě se přesouvají jako kostičky = nesmí se překrývat, ale při přesouvání ve volném prostoru se okolní položky posouvat nebudou.
		/// Pokud tato volba nebude zadána, pak se posun položky nijak neprojeví na jejích sousedních položkách.
		/// </summary>
		ShiftItemsOnSameThread = 0x0010,
		/// <summary>
		/// Při přesouvání této položky se přesouvají i okolní položky (na stejné úrovni).
		/// V této volbě se přesouvají jako by byly všechny položky pevně spojeny.
		/// Pokud tato volba nebude zadána, pak se posun položky nijak neprojeví na jejích sousedních položkách.
		/// </summary>
		FixedLinkItemsOnSameThread = 0x0020,
		/// <summary>
		/// Pokud se při editaci (tam a pak zpátky) uvolní původní umístění, element se tam rád vrátí nebo alespoň přiblíží.
		/// </summary>
		AffinityToInitialTime = 0x0040,
		/// <summary>
		/// Příznak, že tento element je přišpendlený = je jinak zobrazen, a při pohybu jím lze pohybovat pouze přímo.
		/// Pokud by bylo pohybováno sousedním elementem, pak tímto elementem to ani nepohne.
		/// Okolní elementy jej ale mohou překročit.
		/// Pokud máme tedy sadu elementů 10-20-30-40, a z toho element 30 je PinnedItem, a pak pohnu elementem 10 doprava,
		/// pak to způsobí že se posune element 10, návazně element 20, který může přejít doprava i přes element 30 (který je IsPinned).
		/// Ale element 30 se nepohne, a proto se nepohne ani element 40 (ten je navázaný ke 30, a ta se nehýbá).
		/// Element 30 lze posunout jen přímým posunem.
		/// Toto je vizuální obraz stavu IsFixed, pokud CHCEME povolit překrývání operací.
		/// Pokud je současně s hodnotou PinnedItem nastavena hodnota BlockingItem, pak se prvek chová jako BlockingItem (blokování má vyšší prioritu než Pinned).
		/// </summary>,
		PinnedItem = 0x0100,
		/// <summary>
		/// Příznak, že tento element je blokující.
		/// S elementem tohoto typu lze pohybovat ručně, ale pokud dochází k pohybu v jeho okolí, pak se tento element nejen neposune, ale bude blokovat pohyb přes svou pozici.
		/// Chová se jako balvan na cestě.
		/// Pokud máme tedy sadu elementů 10-20-30-40, a z toho element 30 je IsBlocking, a pak pohnu elementem 10 doprava,
		/// pak to způsobí že se posune element 10, návazně element 20, ten ale (na rozdíl od IsPinned) nemůže obejít element 30,
		/// takže element 20 se zastaví na hraně elementu 30, čímž zabrzdí i element 10.
		/// Element 30 lze posunout jen přímým posunem.
		/// Toto je vizuální obraz stavu IsFixed, pokud NECHCEME povolit překrývání operací.
		/// Pokud je současně s hodnotou BlockingItem nastavena hodnota PinnedItem, pak se prvek chová jako BlockingItem (blokování má vyšší prioritu než Pinned).
		/// </summary>
		BlockingItem = 0x0200,
		/// <summary>
		/// Defaultní stav editace : položkou lze pohybovat, resizovat, transponovat, selectovat.
		/// Je nastaveno AffinityToInitialTime.
		/// Okolní prvky se nepohybují (není nastaveno ShiftItemsOnSameThread ani FixedLinkItemsOnSameThread).
		/// </summary>
		DefaultEditingState = Editable | Selectable | AffinityToInitialTime
	}
	/// <summary>
	/// Vzhled elementu - jeho tvar
	/// </summary>
	public enum GraphElementShapeType
	{
		/// <summary>
		/// Obdélníkový element grafu = klasika
		/// </summary>
		Rectangle = 1,
		/// <summary>
		/// Obdélníkový element s vyznačením procentuální spotřeby disponibilní kapacity
		/// </summary>
		CapacityUtilization,
		/// <summary>
		/// Prostý šestiúhelník, pro zobrazení operace.
		/// Šestiúhelník je obdobný jako obdélník, ale levá a pravá hrana jsou "zalomené" jako poněkud tupý úhel znaménka &lt; &gt;.
		/// Pokud jsou v datech šestiúhelníku vyplněny datumy, budou vizuálně zvýrazněny odpovídající části.
		/// </summary>
		Hexagon,
		/// <summary>
		/// Šestiúhelník, s přidanými částmi před a za šestiúhelníkem.
		/// Část před znázorňuje MoveTime, část za šestiúhelníkem znázorňuje časy skladových převodů po dokončení výroby.
		/// </summary>
		HexagonWithTails,
		/// <summary>
		/// Trojúhelník doprava, typicky znázorňuje předání dál v konkrétním čase, bez časového úseku.
		/// Pokud je v elementu nenulový čas, je zobrazeno jako pětiúhelník ("prasátko").
		/// </summary>
		RightTriangle
	}
	/// <summary>
	/// Vizuální druh obsahu uloženého v instanci IDataElementCls.ElementVisualType
	/// Měl by odrážet datovou třídu a/nebo stav záznamu, bude vizuálně odlišeno v grafu.
	/// Konkrétní barvu pro určitý vizuální typ určuje metoda IDataSource.GetColorForElement(), v závislosti na typu grafu a tomto typu.
	/// </summary>
	public enum GraphElementVisualType
	{
		/// <summary>Vizuální typ 1</summary>
		Type1 = 1,
		/// <summary>Vizuální typ 2</summary>
		Type2,
		/// <summary>Vizuální typ 3</summary>
		Type3,
		/// <summary>Vizuální typ 4</summary>
		Type4,
		/// <summary>Vizuální typ 5</summary>
		Type5,
		/// <summary>Vizuální typ 6</summary>
		Type6,
		/// <summary>Vizuální typ 7</summary>
		Type7,
		/// <summary>Vizuální typ 8</summary>
		Type8,
		/// <summary>Vizuální typ 9</summary>
		Type9
	}
	/// <summary>
	/// Stav dat, má vliv na ukládání
	/// </summary>
	public enum GraphEditedState
	{
		/// <summary>Nově založená věta, prázdná, neplatná. Bude se Ignorovat..</summary>
		Ignore = 1,
		/// <summary>Nově založená věta, neuložená. Bude se Insertovat.</summary>
		New,
		/// <summary>Věta načtená z databáze, beze změny. Nic se neprovede.</summary>
		Unchanged,
		/// <summary>Věta načtená z databáze, změněná hodnota. Bude se Updatovat.</summary>
		Edited,
		/// <summary>Věta načtená z databáze, určená ke smazání. Bude se Deletovat.</summary>
		Deleted
	}
	/// <summary>
	/// Směr vztahu mezi dvěma elementy.
	/// Používá se při hledání navazujícího elementu, práce, zakázky, atd.
	/// Reverzní vztah je možno získat statickou metodou : DataRelation.GetElementRelationReverse(...)
	/// </summary>
	public enum ElementRelationOrientation
	{
		/// <summary>Žádný směr</summary>
		None = 1,
		/// <summary>Směr k nadřízenému záznamu</summary>
		Parent,
		/// <summary>Směr k podřízenému záznamu</summary>
		Child,
		/// <summary>Směr k předešlému záznamu, v rámci stejného Tasku/Pass</summary>
		PrevWork,
		/// <summary>Směr k následujícímu záznamu, v rámci stejného Tasku/Pass</summary>
		NextWork,
		/// <summary>Směr k předešlému záznamu, do jiného tasku než je task položky Current, ale stejný dílec</summary>
		PrevTask,
		/// <summary>Směr k následujícímu záznamu, do jiného tasku než je task položky Current, ale stejný dílec</summary>
		NextTask,
		/// <summary>Směr k předešlému záznamu, do jiného dílce (záznam materiálové osy) než je task položky Current</summary>
		PrevAxis,
		/// <summary>Směr k následujícímu záznamu, do jiného dílce (záznam materiálové osy) než je task položky Current</summary>
		NextAxis,
		/// <summary>Směr k souběžnému záznamu (synchronní work v rámci jednoho společného času Time)</summary>
		Parallel,
		/// <summary>Směr k linkovanému záznamu (není ani synchronní, ani nadřízený/podřízený, prostě je přivázaný)</summary>
		Linked
	}
    /// <summary>
    /// Režim viditelnosti popisku elementu (Caption)
    /// </summary>
    public enum CaptionVisibilityMode
    {
        /// <summary>
        /// Výchozí stav: elementy typu Gantt jsou viditelné vždy, elementy TaskLink jsou viditelné jen pokud jsou nějak aktivní (myší, výběrem).
        /// </summary>
        Default = 0,
        /// <summary>
        /// Element má text Caption zobrazen vždy
        /// </summary>
        Always,
        /// <summary>
        /// Element svůj text Caption nezobrazuje nikdy
        /// </summary>
        Hidden,
        /// <summary>
        /// (ToFuture) Podle konfigurace textů
        /// </summary>
        ByConfig
    }
	#endregion
}
